package hu.mapro.gwtui.client.login;

import hu.mapro.gwtui.client.Action;
import hu.mapro.gwtui.client.Handlers;
import hu.mapro.gwtui.client.LoginInterface;
import hu.mapro.gwtui.client.LoginWindow;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import com.google.inject.Singleton;

@Singleton
public class DefaultLoginService implements LoginService {

	LoginRemoteServiceAsync remoteLoginService = GWT.create(LoginRemoteService.class);
	boolean loggedIn = false;
	private LoginWindow loginWindow;
	Handlers loginHandlers = Handlers.newInstance();
	String loginToken;
	private LoginInterface ui;

	@Inject
	public DefaultLoginService(LoginInterface ui) {
		this.ui = ui;
		loginWindow = ui.getLoginWindow();
		loginWindow.setLoginHandler(new Action() {
			@Override
			public void perform() {
				performLogin();
			}
		});

	}
	
	@Override
	public boolean isLoggedIn() {
		return loggedIn;
	}
	
	@Override
	public void addChangeHandler(Action action) {
		loginHandlers.add(action);
	}

	@Override
	public void doLogin() {
		loginWindow.reset();
		loginWindow.show();
	}

	@Override
	public void doLogout() {
		performLogout();
	}

	@Override
	public void removeChangeHandler(Action action) {
		loginHandlers.remove(action);
	}

	protected void performLogin() {
		String username = loginWindow.getUsername();
		String password = loginWindow.getPassword();
		boolean rememberMe = loginWindow.getRememberMe();
		loginWindow.setBusy();
		
		remoteLoginService.login(username, password, rememberMe, new AsyncCallback<String>() {
			@Override
			public void onSuccess(String result) {
				onLogin(result);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				loginWindow.setIdle();
				
				if (caught instanceof LoginBadCredentialsException) {
					ui.alert("Login failed", "Invalid user name or password!", new Action() {
						@Override
						public void perform() {
							loginWindow.retry();
						}
					});
				} else {
					ui.alert("Login Failed", caught.getMessage(), null);
				}
			}
		});
	}

	protected void performLogout() {
		remoteLoginService.logout(loginToken, new AsyncCallback<Void>() {
			@Override
			public void onSuccess(Void result) {
				onLogout();
			}
			
			@Override
			public void onFailure(Throwable caught) {
				ui.alert("Logout Failed", caught.getMessage(), null);
			}
		});
	}

	private void onLogin(String userName) {
		loginToken = userName;
		loggedIn = true;
		ui.setLoginName(userName);
		loginWindow.hide();
		loginHandlers.fire();
	}

	private void onLogout() {
		loginToken = null;
		loggedIn = false;
		ui.clearLoginName();
		loginHandlers.fire();
	}

	public void initLogin(final Action afterInit) {
		remoteLoginService.whoAmI(new AsyncCallback<String>() {
			
			@Override
			public void onFailure(Throwable caught) {
				onLogout();
				afterInit.perform();
			}
			
			@Override
			public void onSuccess(String result) {
				if (result==null) {
					onLogout();
				} else {
					onLogin(result);
				}
				afterInit.perform();
			}
		});
	}
	
	public LoginWindow getLoginWindow() {
		return loginWindow;
	}

	
}
